#include <buola/gui/x11/auto.h>

#include <buola/image/csurface.h>
#include <buola/gui/x11/cx11picture.h>
#include <buola/gui/x11/cx11drawable.h>
#include <buola/gui/x11/cx11display.h>
#include <buola/gui/x11/cx11color.h>
#include <buola/gui/x11/cfixesregion.h>

#include <X11/Xlib.h>
#include <X11/extensions/Xfixes.h>

namespace buola { namespace gui { namespace x11 {

const CX11Picture CX11Picture::mNull;

CX11Picture::CX11Picture()
{
    mPicture=0;
    mOwned=false;
}

CX11Picture::~CX11Picture()
{
    if(mPicture&&mOwned)
    {
        Destroy();
    }
}

inline void FillAttrs(int &pAttrMask,XRenderPictureAttributes &pAttrs,
                                    CX11Picture::EFlags pFlags)
{
    pAttrMask=0;

    if(pFlags&CX11Picture::PICTURE_REPEAT)
    {
        pAttrs.repeat=true;
        pAttrMask|=CPRepeat;
    }
    if(pFlags&CX11Picture::PICTURE_NOEXPOSURES)
    {
        pAttrs.graphics_exposures=false;
        pAttrMask|=CPGraphicsExposure;
    }
    if(pFlags&CX11Picture::PICTURE_INFERIORS)
    {
        pAttrs.subwindow_mode=IncludeInferiors;
        pAttrMask|=CPSubwindowMode;
    }
    if(pFlags&CX11Picture::PICTURE_COMPALPHA)
    {
        pAttrs.component_alpha=true;
        pAttrMask|=CPComponentAlpha;
    }
}

CX11Picture::CX11Picture(Drawable pDrawable,int pDepth,EFlags pFlags)
{
    mPicture=0;
    mOwned=false;
    Create(pDrawable,pDepth,pFlags);
}

CX11Picture::CX11Picture(Drawable pDrawable,Visual *pVisual,EFlags pFlags)
{
    mPicture=0;
    mOwned=false;
    Create(pDrawable,pVisual,pFlags);
}

CX11Picture::CX11Picture(Picture pPicture,bool pOwn)
{
    mPicture=pPicture;
    mOwned=pOwn;
}

void CX11Picture::Create(Drawable pDrawable,int pDepth,EFlags pFlags)
{
    if(mPicture&&mOwned) Destroy();

    int lPict=0;
    switch(pDepth)
    {
    case 32:
        lPict=PictStandardARGB32;
        break;
    case 24:
        lPict=PictStandardRGB24;
        break;
    case 8:
        lPict=PictStandardA8;
        break;
    case 1:
        lPict=PictStandardA1;
        break;
    default:
        throw XNotFound(I18N("Can't find picture format"));
    }

    XRenderPictFormat *lFormat=XRenderFindStandardFormat(
        get_default_x11_display()->GetDisplay(),lPict);

//  if(pDepth==16)
//  {
    //      lFormat=XRenderFindVisualFormat(get_default_x11_display()->GetDisplay(),
    //                  DefaultVisual(get_default_x11_display()->GetDisplay(),0));
//  }

    if(!pFlags)
    {
        mPicture=XRenderCreatePicture(get_default_x11_display()->GetDisplay(),
                    pDrawable,lFormat,0,nullptr);
    }
    else
    {
        int lMask;
        XRenderPictureAttributes lAttrs;

        FillAttrs(lMask,lAttrs,pFlags);
        mPicture=XRenderCreatePicture(get_default_x11_display()->GetDisplay(),
                    pDrawable,lFormat,lMask,&lAttrs);
    }
    mOwned=true;
}

void CX11Picture::Create(Drawable pDrawable,Visual *pVisual,EFlags pFlags)
{
    if(mPicture&&mOwned) Destroy();

    XRenderPictFormat *lFormat=XRenderFindVisualFormat(
            get_default_x11_display()->GetDisplay(),pVisual);

    if(!pFlags)
    {
        mPicture=XRenderCreatePicture(get_default_x11_display()->GetDisplay(),
                    pDrawable,lFormat,0,nullptr);
    }
    else
    {
        int lMask;
        XRenderPictureAttributes lAttrs;

        FillAttrs(lMask,lAttrs,pFlags);
        mPicture=XRenderCreatePicture(get_default_x11_display()->GetDisplay(),
                    pDrawable,lFormat,lMask,&lAttrs);
    }
    mOwned=true;
}

void CX11Picture::Create(Picture pPicture,bool pOwn)
{
    if(mPicture&&mOwned) Destroy();

    mPicture=pPicture;
    mOwned=pOwn;
}

void CX11Picture::CreateSolid(const img::CColor &pColor)
{
    if(mPicture&&mOwned) Destroy();

    Pixmap lPixmap=XCreatePixmap(get_default_x11_display()->GetDisplay(),
                                 get_default_x11_display()->GetDefaultRoot(),1,1,32);
    XRenderPictureAttributes lPA;
    lPA.repeat=true;
    mPicture=XRenderCreatePicture(get_default_x11_display()->GetDisplay(),lPixmap,
                                  XRenderFindStandardFormat(get_default_x11_display()->GetDisplay(),
                PictStandardARGB32),CPRepeat,&lPA);

                XRenderFillRectangle(get_default_x11_display()->GetDisplay(),PictOpSrc,mPicture,
                CX11Color::GetX11Color(pColor)->GetRenderColor(),0,0,1,1);
                XFreePixmap(get_default_x11_display()->GetDisplay(),lPixmap);
    mOwned=true;
}

void CX11Picture::CreateAlpha(unsigned int pAlpha)
{
    if(mPicture&&mOwned) Destroy();

    Pixmap lPixmap=XCreatePixmap(get_default_x11_display()->GetDisplay(),
                                 get_default_x11_display()->GetDefaultRoot(),1,1,8);
    XRenderPictureAttributes lPA;
    lPA.repeat=true;
    mPicture=XRenderCreatePicture(get_default_x11_display()->GetDisplay(),lPixmap,
                                  XRenderFindStandardFormat(get_default_x11_display()->GetDisplay(),
                PictStandardA8),CPRepeat,&lPA);

    XRenderColor lColor;
    lColor.alpha=pAlpha|(pAlpha<<8);

    XRenderFillRectangle(get_default_x11_display()->GetDisplay(),PictOpSrc,mPicture,
                &lColor,0,0,1,1);
                XFreePixmap(get_default_x11_display()->GetDisplay(),lPixmap);
    mOwned=true;
}

void CX11Picture::Destroy()
{
    if(mPicture)
    {
        XRenderFreePicture(get_default_x11_display()->GetDisplay(),mPicture);
        mPicture=0;
    }
}

void CX11Picture::SetClip(const CFixesRegion &pRegion)
{
    XFixesSetPictureClipRegion(get_default_x11_display()->GetDisplay(),mPicture,0,0,
                    pRegion.GetID());
}

void CX11Picture::SetTransform(const CX11Matrix &pMatrix)
{
    XRenderSetPictureTransform(get_default_x11_display()->GetDisplay(),mPicture,
                    const_cast<XTransform*>((const XTransform*)&pMatrix));
}

void CX11Picture::SetFilter(const std::string &pName)
{
    XRenderSetPictureFilter(get_default_x11_display()->GetDisplay(),mPicture,
                    pName.c_str(),nullptr,0);
}

void CX11Picture::FillRect(const CRect_d &pR,const img::CColor &pColor,img::ECompOp pOp)
{
    XRenderFillRectangle(get_default_x11_display()->GetDisplay(),(int)pOp,mPicture,
        CX11Color::GetX11Color(pColor)->GetRenderColor(),(int)pR.l,(int)pR.t,(int)pR.w(),(int)pR.h());
}

void CX11Picture::Composite(const CX11Picture &pSrc,const CX11Picture &pMask,
            const CX11Picture &pDest,const CPoint_d &pSrcPos,
            const CPoint_d &pMaskPos,const CPoint_d &pDestPos,
            const CSize_d &pSize,img::ECompOp pOp)
{
    XRenderComposite(get_default_x11_display()->GetDisplay(),(int)pOp,pSrc.mPicture,pMask.mPicture,
            pDest.mPicture,(int)pSrcPos.x,(int)pSrcPos.y,(int)pMaskPos.x,
            (int)pMaskPos.y,(int)pDestPos.x,(int)pDestPos.y,(int)pSize.x,
            (int)pSize.y);
}

/*namespace x11*/ } /*namespace gui*/ } /*namespace buola*/ }
